package menus.flower.recognizers;

import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;

import menus.common.AbstractGestureAnalyzer;

import fr.lri.swingstates.gestures.Gesture;

/**
 * Class used to recognize user-drawn gestures in a Flower Menu. 
 * The method used is a k-nearest-neighbor with simple gesture data.  
 * 
 * @author mathieu
 *
 */
public abstract class AbstractFlowerGestureRecognizer extends AbstractGestureAnalyzer {
	
	
	// Gesture data table indexes
	
	protected static final int START_ANGLE = 0;
	protected static final int END_ANGLE = 1;
	protected static final int ROT_DIRECTION = 2;
	protected static final int ID = 3;
	protected static final int SCORE = 4;
	
	
	// Default gesture angles analyzing intervals
	
	protected static double[] startAngleInterval = {.1, .46};
	protected static double[] endAngleInterval = {.8, .99};
	
	/**
	 * Item IDs to be considered during the analysis
	 */
	protected HashSet<Integer> availableItemIDs;
	
	
	
	// ----------------------------------------------------------------- XXX

	
	
	public AbstractFlowerGestureRecognizer(HashSet<Integer> availableItemIDs) {
		this.availableItemIDs = availableItemIDs;
	}
	
	public abstract int recogniseGesture(Gesture gesture);
	
	protected double[] analyzeGesture(Gesture gesture){
		
		double [] result = new double[3];
		
		// Computing the lengths and angles for each point
		
		extractDataFromGesture(gesture);
		
		Point2D cursor;
		
		// Sum of the angular differences between each point
		double totalAngle = 0;
		
		double angle;
		double previousAngle = Math.atan2(
				gesture.getPoints().get(0).getY() - gesture.getPoints().get(1).getY(),
				gesture.getPoints().get(1).getX() - gesture.getPoints().get(0).getX()
		);
		double difference;

		cursor = gesture.getPoints().get(0);
		
		for (int i = 1; i < gesture.getPoints().size(); i++){
			
			angle = Math.atan2(
					cursor.getY() - gesture.getPoints().get(i).getY(),
					gesture.getPoints().get(i).getX() - cursor.getX()
			);
			
			// smoothing
			difference = angle - previousAngle;
			
			if (difference > Math.PI)
				difference -= 2*Math.PI;
			else if (difference < -Math.PI)
				difference += 2*Math.PI;
			
			totalAngle += difference;
			
			previousAngle = angle;
			
			cursor = gesture.getPoints().get(i);
		}
		
		Point2D[] points = {
				getClosestPoint(gesture, startAngleInterval[0]),
				getClosestPoint(gesture, startAngleInterval[1]),
				getClosestPoint(gesture, endAngleInterval[0]),
				getClosestPoint(gesture, endAngleInterval[1])
		};
		
		result[START_ANGLE] = Math.atan2(
				points[0].getY() - points[1].getY(), 
				points[1].getX() - points[0].getX()
		);
		
		result[END_ANGLE] = Math.atan2(
				points[2].getY() - points[3].getY(), 
				points[3].getX() - points[2].getX()
		);
		
		result[ROT_DIRECTION] = Math.signum(totalAngle);
		
		return result;
	}
	
	protected Point2D getClosestPoint(Gesture gesture, double ratio){
		
		// First we find the first point further than the ratio, 
		// then we check which of this point and the one before is the closest from the ratio
		
		int index;
		for (index = 0; lengths[index] < strokeLength * ratio; index++);
		
		if (lengths[index] - strokeLength * ratio < strokeLength * ratio - lengths[index-1] )
			return gesture.getPoints().get(index);
		
		return gesture.getPoints().get(index-1);
		
	}
	
}
